package com.qianheng.kit.base.java.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;


public class VolatialDemo {
    public static class MyDemo {
        //volatile
        volatile int num = 0;

        public void add1() {
            this.num++;
        }
    }


    public static void main(String[] args) throws InterruptedException {
        MyDemo myDemo = new MyDemo();

//        testVisibility(myDemo);

        testAtomicity(myDemo);

    }

    /**
     * 测试volatial原子性 : 100个线程, 各执行1000次加法, 结果应该为10W , 实际有volatile修饰为六千多, 无volatile修饰为八千多.
     * 奇怪, 不修饰反而更高,可能线程执行太快,B线程是在A线程执行结束之后才开始
     * @param myDemo
     * @throws InterruptedException
     */
    private static void testAtomicity(MyDemo myDemo) throws InterruptedException {
        //初始化100个线程
        List<Thread> threads = new ArrayList<>(100);
        for (int i = 0; i < 100; i++) {
            threads.add(
                    new Thread() {
                        @Override
                        public void run() {
                            for (int j = 0; j < 1000; j++) {
                                myDemo.add1();
                            }
                        }
                    }
            );

        }
        //线程执行
        for (Thread thread : threads) {
            thread.start();
        }

        //等待
        TimeUnit.SECONDS.sleep(3);
        while (Thread.activeCount()>2){
        }
        System.out.println("原子性测试结束, 结果为: " + myDemo.num);

    }

    /**
     * 测试volatile具有可见性. MyDemo.num 不被valolatile修饰时, 线程内存没有同步, 一直等待;  修饰后,立即同步,不会一直等待.
     *
     * @param myDemo
     */
    private static void testVisibility(MyDemo myDemo) {
        new Thread() {
            @Override
            public void run() {
                System.out.println(String.format("执行线程77:%s add1", Thread.currentThread().getName()));
                myDemo.add1();
                System.out.println(String.format("执行线程:%s 结束, 结果:%d", Thread.currentThread().getName(), myDemo.num));
            }
        }.start();

        while (myDemo.num == 0) {
            //空等待.  这里不能线程sleep, 否则唤醒后会同步主内存, 导致无法验证
        }
        System.out.println("testVisibility执行结束,结果:" + myDemo.num);
    }
}
